//
//  GYXNetworkManager.swift
//  GYXWeibo
//
//  Created by Twisal on 2017/1/12.
//  Copyright © 2017年 Twisal. All rights reserved.
//

import UIKit
import AFNetworking

enum GYXHttpMethod {
    case GET
    case POST
}

class GYXNetworkManager: AFHTTPSessionManager {

    /// 单例的写法
    static let shared : GYXNetworkManager = {
        let instance = GYXNetworkManager()
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
        return instance
    }()

    
    /// 用户账号模型
    lazy var userAccount = GYXUserAccount()
    
    /// 用户登录标记
    var userLogon: Bool {
        return userAccount.access_token != nil
    }
    
    /// 专门负责拼接 token 的网络请求方法
    ///
    /// - parameter method:     GET / POST
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    /// - parameter name:       上传文件使用的字段名，默认为 nil，不上传文件
    /// - parameter data:       上传文件的二进制数据，默认为 nil，不上传文件
    /// - parameter completion: 完成回调
    func tokenRequest(method: GYXHttpMethod = .GET, URLString: String, parameters: [String: AnyObject]?, name: String? = nil, data: Data? = nil, completion: @escaping (_ json: AnyObject?, _ isSuccess: Bool) -> ()) {
        // 1,判断accessToken是否存在
        guard let token = userAccount.access_token else {
            print("token不存在, 请登录")
            // 发送通知, 通知用户重新登录
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: nil)
            completion(nil, false)
            return
        }
        
        // 2, 判断参数是否为空
        var params = parameters
        if params == nil {
            params = [String : AnyObject]()
        }
        
        // 3, 为参数插入token
        params!["access_token"] = token as AnyObject?
        
        
        // 4, 判断是否是上传文件
        if let name = name, let data = data {
            upLoad(URLString: URLString, parameters: params, name: name, data: data, completion: completion)
        } else {
            
            request(method:method, URLString: URLString, parameters: params, completion: completion)
        }
        
    }
    
    // MARK: - 封装 AFN 方法
    /// 上传文件必须是 POST 方法，GET 只能获取数据
    /// 封装 AFN 的上传文件方法
    ///
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    /// - parameter name:       接收上传数据的服务器字段(name - 要咨询公司的后台) `pic`
    /// - parameter data:       要上传的二进制数据
    /// - parameter completion: 完成回调
    func upLoad(URLString: String, parameters: [String: AnyObject]?, name: String, data: Data, completion: @escaping (_ json: AnyObject?, _ isSuccess: Bool) -> ()) {
        // AFMultipartFormData
        post(URLString, parameters: parameters, constructingBodyWith: { (formData) in
            // 创建 formData
            /**
             1. data: 要上传的二进制数据
             2. name: 服务器接收数据的字段名
             3. fileName: 保存在服务器的文件名，大多数服务器，现在可以乱写
             很多服务器，上传图片完成后，会生成缩略图，中图，大图...
             4. mimeType: 告诉服务器上传文件的类型，如果不想告诉，可以使用 application/octet-stream
             image/png image/jpg image/gif
             */
            formData.appendPart(withFileData: data, name: name, fileName: "xxx", mimeType: "application/octet-stream")

        }, progress: nil, success: { (_, json) in
            // 完成回调
            completion(json as AnyObject, true)
        }) { (task, error) in
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                print("token过期了")
                // 发送通知, 提示用户登录
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad token")
                
            }
            print("网络请求错误信息: \(error)")
            completion(nil, false)

        }
    }
    
    /// 封装 AFN 的 GET / POST 请求
    ///
    /// - parameter method:     GET / POST
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    /// - parameter completion: 完成回调[json(字典／数组), 是否成功]
    func request(method: GYXHttpMethod = .GET, URLString: String, parameters: [String: AnyObject]?, completion: @escaping (_ json: AnyObject?, _ isSuccess: Bool) -> ()) {
        
        // 定义闭包
        let success = { (task: URLSessionDataTask, json: Any?) -> () in
            completion(json as AnyObject, true)
        }
        // 针对 403 处理用户 token 过期
        // 对于测试用户(应用程序还没有提交给新浪微博审核)每天的刷新量是有限的！
        // 超出上限，token 会被锁定一段时间
        // 解决办法，新建一个应用程序！
        let failure = { (task: URLSessionDataTask?, error: Error) -> () in
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                print("token过期了")
                // 发送通知, 提示用户登录
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad token")
                
            }
            print("网络请求错误信息: \(error)")
            completion(nil, false)
        }
        
        if method == .GET {
            get(URLString, parameters: parameters, progress: nil, success: success, failure: failure)
        } else {
            post(URLString, parameters: parameters, progress: nil, success: success, failure: failure)        }
    }
    
}
